package com.源码分析;

import java.util.Date;

import org.junit.Test;

import reactor.core.publisher.Mono;

public class DeferDemo {

	// defer工厂方法创建一个序列，并在订阅时确定其行为，因此可以为不同的订阅者生成不同的数据
	// 此代码可以将对sessionId的验证推迟到实际订阅之后，相反，requestDefer2在调用时就进行验证(也就是说可能根本不会发生订阅)
	private Mono<String> requestDefer(int sessionId){
		return Mono.<String>defer(() ->
				isValid(sessionId) ? Mono.<String>fromCallable(() -> requestUser(sessionId))
						: Mono.error(new RuntimeException("invalid sessionId")));
	}

	private String requestUser(int sessionId) {
		return null;
	}

	private boolean isValid(int sessionId) {
		return false;
	}
	
	@Test
	// mono defer方法创建数据源属于懒汉型，与Mono.just等创建数据源则是饿汉型，下面看一个例子：
	// 我们可以看到，创建了两个数据源，一个使用Mono.just创建，一个用Mono.defer创建，
	// （1）首先分别通过lambda表达式订阅这两个publisher，可以看到两个输出的时间都是10:22:51；
	// （2）延迟5秒钟后重新订阅，Mono.just创建的数据源时间没变，但是Mono.defer创建的数据源时间相应的延迟了5秒钟；
	// 原因在于：
	// Mono.just会在声明阶段构造Date对象，只创建一次；
	// 但是Mono.defer却是在subscribe阶段才会创建对应的Date对象，每次调用subscribe方法都会创建Date对象；
	public void defer(){
		//声明阶段创建DeferClass对象
		Mono<Date> m1 = Mono.just(new Date());
		Mono<Date> m2 = Mono.defer(()->Mono.just(new Date()));
		m1.subscribe(System.out::println);
		m2.subscribe(System.out::println);
		
        //延迟5秒钟
		try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		m1.subscribe(System.out::println);
		m2.subscribe(System.out::println);
	}

}
